﻿using System.IO;
using System.Xml;
using System.Xml.Schema;

namespace HexunMicroblogging.Schema
{
    /// <summary>
    /// The Validation Result enum type.
    /// </summary>
    public enum ValidationResult
    {
        /// <summary>
        /// Validate successful.
        /// </summary>
        Success,

        /// <summary>
        /// Indicates a validation error occurred when validating the instance document.
        /// </summary>
        Error,

        /// <summary>
        /// Indicates that a validation event occurred that is not an error, but warning.
        /// </summary>
        Warning
    }

    /// <summary>
    /// Class for schema validation.
    /// </summary>
    class SchemaValidation
    {
        #region Private fields

        /// <summary>
        /// The schema for validate.
        /// </summary>
        private string schema;

        /// <summary>
        /// Instance of validation result.
        /// </summary>
        private ValidationResult validationResult;

        #endregion

        #region Constructor

        public SchemaValidation(string schema)
        {
            // TODO: Complete member initialization
            this.schema = schema;
        }

        #endregion

        #region Public methods

        /// <summary>
        /// Validate schema.
        /// </summary>
        /// <param name="xmlData">Xml string for validate.</param>
        /// <returns>Return validate result.</returns>
        public ValidationResult ValidateSchema(string xmlData)
        {
            XmlReaderSettings validationSettings = new XmlReaderSettings();
            XmlReader xsdXmlReader = XmlReader.Create(new StringReader(schema));

            // Get target namespace from schema.
            string targetNameSpace = GetTargetNamespace(schema);

            validationSettings.Schemas.Add(targetNameSpace, xsdXmlReader);
            validationSettings.ValidationType = ValidationType.Schema;
            validationSettings.ConformanceLevel = ConformanceLevel.Document;
            validationSettings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
            validationSettings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);
            validationResult = ValidationResult.Success;

            XmlReader validationReader = XmlReader.Create(new StringReader(xmlData), validationSettings);
            while (validationReader.Read()) ;

            return validationResult;
        }

        #endregion

        #region Helper methods

        /// <summary>
        /// Get target namespace of full schema string.
        /// </summary>
        /// <param name="fullSchema">Full schema string.</param>
        /// <returns>Target namespace.</returns>
        private string GetTargetNamespace(string fullSchema)
        {
            XmlDocument xnlDoc = new XmlDocument();
            xnlDoc.LoadXml(fullSchema);

            if (xnlDoc.ChildNodes.Count <= 1)
            {
                return null;
            }

            XmlAttributeCollection attributeList = xnlDoc.ChildNodes[1].Attributes;
            foreach (XmlAttribute attribute in attributeList)
            {
                if (attribute.Name == "targetNamespace")
                    return attribute.Value;
            }

            return null;
        }

        /// <summary>
        /// Validate call back funtion.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void ValidationCallBack(object sender, ValidationEventArgs args)
        {
            if (args.Severity == XmlSeverityType.Warning)
                validationResult = ValidationResult.Warning;
            else
                validationResult = ValidationResult.Error;
        }

        #endregion
    }
}
